package com.simple_frame.aspect;

import com.alibaba.fastjson2.JSON;
import com.simple_frame.utils.IpUtils;
import com.simple_frame.utils.Result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.support.MultipartFilter;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Component
@Aspect
@Slf4j
public class LogAspect {
    
    @Pointcut("execution(* com.simple_frame.controller..*(..))")
    public void allInterface() {
    }
    
    @Pointcut("execution(void com.simple_frame.controller..*(..))")
    public void allVoidInterface() {
    }
    
    @Around("allVoidInterface()")
    public void doVoidAround(ProceedingJoinPoint pjp) throws Throwable {
        // 记录日志
        printVoidLog(pjp);
    }
    
    @Around("allInterface() && !allVoidInterface()")
    public Result doAround(ProceedingJoinPoint pjp) throws Throwable {
        // 记录日志
        return printLog(pjp);
    }
    
    private void printVoidLog(ProceedingJoinPoint pjp) throws Throwable {
        String args = JSON.toJSONString(filterArgs(pjp.getArgs()));
        HttpServletRequest request = ((ServletRequestAttributes)
                Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String ip = IpUtils.getIpAddr(request);
        Throwable exception = null;
        boolean haveException = false;
        try {
            pjp.proceed();
        } catch (Throwable e) {
            haveException = true;
            exception = e;
        }
        log.info("""
                        
                        \r=======================================
                        \r请求地址:{}\s
                        \r请求方式:{}\s
                        \r请求参数:{}\s
                        \rip地址:{}\s
                        \r=======================================
                        \r""",
                request.getRequestURI(),
                request.getMethod(),
                args,
                ip
        );
        if (haveException) {
            throw exception;
        }
    }
    
    /**
     * 日志打印
     */
    public Result printLog(ProceedingJoinPoint pjp) throws Throwable {
        String args = JSON.toJSONString(filterArgs(pjp.getArgs()));
        HttpServletRequest request = ((ServletRequestAttributes)
                Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String ip = IpUtils.getIpAddr(request);
        Exception exception = null;
        Integer code;
        Result proceed = null;
        boolean haveException = false;
        try {
            proceed = (Result) pjp.proceed();
            code = proceed.getCode();
        } catch (Exception e) {
            haveException = true;
            code = 500;
            exception = e;
        }
        log.info("""
                        
                        \r=======================================
                        \r请求地址:{}\s
                        \r请求方式:{}\s
                        \r请求参数:{}\s
                        \rip地址:{}\s
                        \r响应码:{}\s
                        \r=======================================
                        \r""",
                request.getRequestURI(),
                request.getMethod(),
                args,
                ip,
                code
        );
        if (haveException) {
            throw exception;
        }
        return proceed;
        
    }
    
    
    /**
     * 过滤参数
     *
     * @param args 排除与 HttpServletRequest HttpServletResponse MultipartFilter 有关的参数
     * @return 符合要求的参数集合
     */
    private List<Object> filterArgs(Object[] args) {
        return Arrays.stream(args).filter(object -> !(object instanceof MultipartFilter)
                && !(object instanceof HttpServletRequest)
                && !(object instanceof HttpServletResponse)
        ).collect(Collectors.toList());
    }
}
